
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "datarcver.h"


/** ***************************************************************************
 * @use_for:数据接收类
 * @data:2019-9-11
 * @author:socbis
 * @special_note: 将 DebugLevel 调为 DebugTmp 显示所有调试信息
 * */



#ifdef DebugLevel
#undef DebugLevel
#define     DebugLevel                  DebugLog
#endif /* #ifdef DebugLevel */

#define GetOffset(p, initnal)   ((uint32_t)((char*)p - (char*)(initnal)))


static uint32_t PackParser(struct DataReceiver* this, void* arg);
static void HeadChecker(struct DataReceiver* this, void* arg);
static DataMan_t* CreateBuf(struct DataReceiver* this, 
                                    uint32_t buflen, uint32_t id);
static void SelectBufFree(struct DataReceiver* this);
static void AllBufFree(struct DataReceiver* this);
static DataMan_t* SelectBuf(DataReceiver_t* this, uint32_t id);

/** ###########################################################################
 * Use For      ----  初始化一个在堆区或全局区创建的数据接受器
 * Param        ----  使用mancnt选择创建模式：
 *                      mancnt = 1 使用单管理器模式，此时使用select指向管理器，buflen
 *                              参数指明创建buf大小
 *                      mancnt = n 使用多管理器模式，此时buflen无效，用户需要在需要的
 *                              时候，使用CreateBuf函数去创建管理器，该模式适用于数据流
 *                              为乱序的分id接收的模型，旨在使用不同的id区分不同的数据
 *                              流,保证总线上来自不同设备的数据不会混乱
 * 
 * Note :   在程序中，管理器意义等同于Buf。
 *          上述提到的需要的时候创建管理器，可以理解为总线上来了一个新的设备id，意为着一个
 *          新的数据流到来了。
 * */
bool DataReveiver_Init(struct DataReceiver* new, uint32_t mancnt, 
                                                                uint32_t buflen)
{
    if (new == NULL) {
        return false;
    }
    DebugT("DataReveiver_Init :  ");
    memset(new, 0, sizeof(struct DataReceiver));
    new->PackParser = PackParser;
    new->HeadChecker = HeadChecker;
    
    new->listlen = 1;
    if (mancnt == 1) {
        DebugT("Single mode\n");
        new->select = (DataMan_t*)malloc(sizeof(DataMan_t));
        new->select->base = (uint8_t*)malloc(buflen);
        new->muinx = -1;
    }
    else if (mancnt > 1){
        DebugT("Multiple mode\n");
        new->manlist = (DataMan_t**)malloc(sizeof(DataMan_t*) * mancnt);
        new->muinx = 0;
        new->listlen = mancnt;
        new->CreateBuf = CreateBuf;
        new->SelectBufFree = SelectBufFree;
        new->AllBufFree = AllBufFree;
        new->SelectBuf = SelectBuf; 
    }
    return true;
}






/** ***************************************************************************
 * Use For      ---- 向垃圾池里倾倒数据，如果未定义相关函数，则作警告
 * Para         ---- clear > 为1，清空垃圾池，并调用用户的处理函数
 *                          为0，仅倾倒数据，不做处理
 * */
static inline uint8_t TrydDump(struct DataReceiver* this, 
                                    bool clear,
                                    uint32_t dumplen, 
                                    void* arg)
{
    if (this->DumppoolProcessor == NULL ||
        this->dumppool == NULL) 
    {
        DebugW("Warning : you did not define the error handling method "
                    ":'DumppoolProcessor' & 'dumppool' \n");
        return 0;
    }
    
    if (dumplen) {
        /* 复制数据到垃圾池 */
        memcpy((void*)(this->dumppool + this->poollen), this->p_head, dumplen);
        this->poollen += dumplen;
    }

    /**
     * @note:调用用户的垃圾处理函数
     * */
    if (clear) {
        this->mo.errcnt++;
        this->DumppoolProcessor(this, arg);
        this->poollen = 0;
    }
    return 1;
}


/** ***************************************************************************
 * Use For     ---- 分析消息包，分离粘包，检验包完整与否
 * */
static uint32_t PackParser(struct DataReceiver* this, void* arg)
{
    uint8_t* p_search;
    uint32_t parsedlen = 0;
    uint32_t ret = 0;

    this->p_head = this->select->base;
    this->p_next = this->select->base;
    
    bool recheck = false;

HeadCheck:
    this->HeadChecker(this, arg);
    if (this->packtype == PackType_Invalid) {
        parsedlen = this->select->readlen;
        goto DataCleaning;
    }
    /**
     * 有头无尾,当前包未接受完成 */
    else if (this->packtype == PackType_HalfPack) {
        parsedlen = GetOffset(this->p_head, this->select->base);
        goto DataCleaning;
    }
    /* 包长非法 */
    else if (this->packtype == PackType_LenthIlliegal) {
        DebugE("****** Error, pack lenth illegal, omit! ******\n");
        // p_search = (uint8_t*)this->SearchHead(this->p_head, this->readlen);
        // if (p_search == NULL) {
        //     parsedlen = this->readlen;
        //     goto DataCleaning;
        // }
        parsedlen = this->select->readlen;
        TrydDump(this, 0, parsedlen, arg);
        goto DataCleaning;
    }

PackCheck:
    /* 接收到完整的包 */
    if (this->select->readlen == GetOffset(this->p_next, this->select->base)) {
        DebugT("msglen == packlen\n");
        parsedlen = GetOffset(this->p_next, this->select->base);
        goto PackProcess;
    }
    /* 可能接收到完整包，需检查该包是否有包尾,以及包尾之后是否有新的包头 */
    else if (this->select->readlen > GetOffset(this->p_next, this->select->base)) {
        DebugT("msglen > packlen\n");
        recheck = true;
        goto PackProcess;
    }
    /**
     * 有头无尾,当前包未接受完成 */
    else {
        parsedlen = GetOffset(this->p_head, this->select->base);
        goto DataCleaning;
    }
PackProcess:
    /* 如果垃圾池里有多余数据，先处理掉 */
    if (this->poollen > 0) {
        TrydDump(this, 1, 0, arg);
    }
    if (this->Check != NULL) {
        if (this->Check(this) == 0) {
            this->PackProcessor(this, arg);
        }
        else {
            DebugE("Package Check error\n");
            TrydDump(this, 1, this->packlen, arg);
        }
    }
    else {  this->PackProcessor(this, arg);  }
    
    if (recheck == true) {
        recheck = false;
        this->p_head = this->p_next;
        DebugT("recheck\n");
        goto HeadCheck;
    }

DataCleaning:
    /* 整理未处理数据到基地址处 */
    if (parsedlen > 0) {
        DebugL("parsedlen = %d\n", parsedlen);
        this->select->readlen -= parsedlen;
        memcpy(this->select->base, this->select->base + parsedlen, this->select->readlen);
    }
    return parsedlen;
}



/** ***************************************************************************
 * Use For      ---- HeadChecker 子函数
 * */
static void HeadChecker(struct DataReceiver* this, void* arg)
{
    void* p_search = NULL;

    /* 已分析的数据长度*/
    #define ParsedLen   GetOffset(this->p_next, this->select->base)
    /* 未分析的数据长度 */
    #define RemainLen   (this->select->readlen - ParsedLen)
recheck:
    DebugT("ParsedLen = %d\n",ParsedLen);

    this->IsHead(this);
    
    /* 无头包, this->packtype != PackType_HalfPack 且 小于零 */
    if (this->packtype == PackType_Invalid) {

        if (RemainLen >= this->minheadlen) {
            /** @note:
             * 调用用户编写的头搜索函数，尝试在剩余的数据中搜索包头*/
            p_search = this->SearchHead(this->p_head, RemainLen);
        }

        if (p_search != NULL) {
            /* 找到新的头，计算要丢弃的数据量，复制数据到倾斜池 */
            uint32_t dumplen = GetOffset(p_search, this->p_head);
            TrydDump(this, 1, dumplen, arg);

            this->p_head = p_search;
            this->p_next = this->p_head;
            this->mo.errcnt++;
            goto recheck;
        }

        /* 未找到新的头，计算要丢弃的数据量，复制数据到倾斜池 */
        uint32_t dumplen = this->select->readlen - GetOffset(this->p_head, 
                                                this->select->base);
        TrydDump(this, 0, dumplen, arg);
        return;
    }
}


/** ***************************************************************************
 * Use For  ---- 在使用多缓存接受模式时使用。
 *              使用manlist中最小的未使用的下标元素，创建新的数据管理器(也称Buf)
 * Note     ---- 使用多缓存接受模式旨在区分不同设备的数据流，一般使用id区分，因此创建
 *               新的管理器时需要指定一个id标记，用于区分其他的流，也便于后续的数据能到
 *               达正确的位置(流可能是分多次到达的)
 * */
DataMan_t* CreateBuf(DataReceiver_t* this, uint32_t buflen, uint32_t id)
{
    if (this->muinx == this->listlen) {
        DebugE("CreateBuf failed, manlist max = %d, overflow! \n", this->listlen);
    }
    DataMan_t* newbuf = (DataMan_t*)malloc(sizeof(DataMan_t));
    DebugB("CreateBuf newbuf = %p\n", newbuf);
    newbuf->buflen = buflen;
    newbuf->readlen = 0;
    newbuf->base = (uint8_t*)malloc(buflen);

    this->select = newbuf;
    this->select->id = id;
    this->manlist[this->muinx++] = newbuf;
    return newbuf;
}

/** ***************************************************************************
 * Use For  ---- 在使用多缓存接受模式时使用
 * */
DataMan_t* SelectBuf(DataReceiver_t* this, uint32_t id)
{
    DebugB("%s\n", __func__);
    DebugB(" this->muinx = %d\n", this->muinx);
    for(int i = 0; i < this->muinx; i++) {
        DebugB("manid = %#x id = %d\n", this->manlist[i]->id, id);
        if (this->manlist[i]->id == id) {
            return this->select = this->manlist[i];
        }
    }
    return NULL;
}

/** ***************************************************************************
 * Use For  ---- 在使用多缓存接受模式时使用,单管理器模式下不允许释放SelectBuf
 * */
void SelectBufFree(DataReceiver_t* this)
{
    if (this->manlist == NULL) {
        DebugE("Single Buf mode is allowed to release SelectBuf\n");
        return;
    }
    for (int i = 0; i < this->muinx; i++) {
        if (this->select == this->manlist[i]) {
            this->manlist[i] = this->manlist[this->muinx - 1];
            break;
        }
    }
    free(this->select->base);
    free(this->select);
    this->muinx--;
}

/** ***************************************************************************
 * Use For  ---- 在使用多缓存接受模式时使用
 * */
void AllBufFree(DataReceiver_t* this)
{
    for (int i = 0; i < this->muinx; i++) {
        free(this->manlist[i]->base);
        free(this->manlist[i]);
    }
}

/** ###########################################################################
 * Use For  ---- 为一个新的数据接收器初始化垃圾处理器
 * Param    ---- new > 新接收器, poolmax > 垃圾池长度, DumpProcessor > 处理函数
 * */
void DumppoolProcessorInit(struct DataReceiver* new, uint32_t poolmax, 
                    void (*DumpProcessor)(struct DataReceiver* , void* ))
{
    new->DumppoolProcessor = DumpProcessor;
    new->poolmax = poolmax;
    new->dumppool = (uint8_t*)malloc(poolmax);
}


/** ###########################################################################
 * Use For      ---- 这个函数基本不可能用到，因为数据接受常常是作为一个常驻任务存在的
 * */
void DataReceiver_Deinit(struct DataReceiver* del)
{
    /* 多缓存模式 */
    if (del->manlist == NULL) {
        for (int i = 0; i < del->muinx; i++) {
            free(del->manlist[i]->base);
            free(del->manlist[i]);
        }
        free(del->manlist);
    }
    /* 单缓存模式 */
    else {
        free(del->select->base);
        free(del->select);
    }
    /* 释放倾斜池 */
    if (del->dumppool != NULL) {
        free(del->dumppool);
    }
}




